package com.wrupple.muba.catalogs.server.state.impl;

import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.google.gwt.event.shared.EventBus;
import com.wrupple.muba.catalogs.client.activity.CatalogActivity;
import com.wrupple.muba.catalogs.client.channels.ICatalogVegetateChannel;
import com.wrupple.muba.catalogs.server.domain.CatalogActionStateBag;
import com.wrupple.muba.catalogs.server.service.CatalogDataAccessObject;
import com.wrupple.muba.catalogs.server.service.CatalogEntrySerializationService;
import com.wrupple.muba.catalogs.server.service.CatalogTokenInterpret;
import com.wrupple.muba.catalogs.server.service.GenericCatalogDataAccessObject;
import com.wrupple.muba.catalogs.server.state.catalogEngine.CatalogRequestInterpret;
import com.wrupple.muba.common.domain.FilterData;
import com.wrupple.muba.common.shared.StateTransition;
import com.wrupple.vegetate.client.module.services.logic.FilterDataSerializationService;
import com.wrupple.vegetate.domain.CatalogObject;
import com.wrupple.vegetate.domain.exceptions.DataLayerException;

public class SimpleCatalogRequestInterpret implements CatalogRequestInterpret {
	CatalogActionStateBag parameter;
	private FilterDataSerializationService fdata;
	private CatalogEntrySerializationService entry;
	private Map<String, String> pathParameters;
	CatalogTokenInterpret interpret;
	private GenericCatalogDataAccessObject<? extends CatalogObject> fallbackDao;

	public SimpleCatalogRequestInterpret(CatalogActionStateBag stateBag,
			GenericCatalogDataAccessObject<? extends CatalogObject> dao,
			FilterDataSerializationService fdata,
			CatalogEntrySerializationService entry,
			CatalogTokenInterpret interpret) {
		super();
		this.parameter = stateBag;
		this.fdata = fdata;
		this.entry = entry;
		this.interpret = interpret;
		this.fallbackDao = dao;
	}

	@Override
	public void start(HttpServletRequest request,
			StateTransition<CatalogActionStateBag> onDone, EventBus bus) {
		String[] rawData = (String[]) request.getParameterMap().get(
				ICatalogVegetateChannel.CHANNE_PARAMETER_NAME);
		String function=request.getParameter(CatalogActionStateBag.CALLBACK_FUNCTION_PARAMETER);
		parameter.setCallbackFunctionName(function);
		parameter.setRawData(rawData);

		String targetAction = pathParameters.get(CatalogActivity.CATALOG_ACTION_PARAMETER);
		String targetEntryId = pathParameters.get(CatalogActivity.CATALOG_ENTRY_PARAMETER);
		String pressumedCatalogId = pathParameters.get(CatalogActivity.CATALOG_ID_PARAMETER);
		
		try {
			Class<? extends CatalogObject> targetCatalogId = interpret
					.interpretCatalogNameAsJavaClass(pressumedCatalogId);
			

			boolean isFilterableRequest = isFilterableRequest(targetAction,
					targetEntryId);

			parameter.setTargetAction(targetAction);
			parameter.setTargetCatalogName(pressumedCatalogId);
			parameter.setTargetEntryId(targetEntryId);

			CatalogDataAccessObject<? extends CatalogObject> targetDao = getTargetDao(targetCatalogId);
			parameter.setTargetCatalogDao(targetDao);
			if (isFilterableRequest) {
				FilterData[] filters;
				if (rawData == null) {
					filters = new FilterData[0];
				} else {
					filters = new FilterData[rawData.length];
				}
				String rawFilter;
				FilterData filter;
				for (int i = 0; i < filters.length; i++) {
					rawFilter = rawData[i];

					try {
						
						filter = fdata.deserialize(rawFilter);
						
					} catch (Exception e) {
						filter = new FilterData();
						filter.setStart(0);
						filter.setEnd(100);
						parameter.setCollectedException(e);
						System.err.println("Failed to deserialize filter data and default filters will be used");
					}

					filters[i] = filter;
				}
				parameter.setFilterData(filters);
			} else {
				if (rawData == null) {
					// this is not gonna work
				} else {
					CatalogObject[] entries = new CatalogObject[rawData.length];
					String rawEntry;
					CatalogObject entry;
					try {
						for (int i = 0; i < entries.length; i++) {
							rawEntry = rawData[i];

							entry = this.entry.deserialize(targetCatalogId,rawEntry);

							entries[i] = entry;
						}
						parameter.setData(entries);
					} catch (IOException e) {
						parameter.setCollectedException(e);
					}
				}
			}
		} catch (DataLayerException e1) {
			parameter.setCollectedException(e1);
		}
		
		
		if(CatalogActivity.READ_ACTION.equals(targetAction)){
			assert (parameter.getFilterData()!=null || parameter.getTargetEntryId()!=null):"Neither filters nor entry id was specified for this reading action";
		}
		onDone.setResultAndFinish(parameter);
	}

	private CatalogDataAccessObject<? extends CatalogObject> getTargetDao(Class<? extends CatalogObject> targetCatalogId) {
		Class clazz = targetCatalogId;
		fallbackDao.setClass(clazz);
		return fallbackDao;
	}

	private boolean isFilterableRequest(String targetAction,
			String targetEntryId) {
		return (CatalogActivity.SUMMARY_ACTION.equals(targetAction) || (CatalogActivity.READ_ACTION
				.equals(targetAction) && targetEntryId == null));
	}

	@Override
	public void setPathParameters(Map<String, String> pathParameters) {
		this.pathParameters = pathParameters;
	}


}
